﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;


namespace GUI2
{
    public partial class Form1 : Form
    {
        // Create Variable
        Byte AlarmLevel1, AlarmLevel2;
        int BaudRate;
        //UInt16 i = 0;

        //Hospital Number
        string Hospital_Number;

        Byte[] OxygenSaturation = new Byte[14];
        Byte[] FiO2_Value = new Byte[14];

        //Check Connected ?
        bool connected, condition = false;
        //Setting Serial Port
        string[] ports = SerialPort.GetPortNames();                                     //Get Port Name from your computer

        //Define Value for Data Packaging
        Byte[] Data_Package = new Byte[40];                                             //Package of Data is lenght 40 Bytes
        const Byte Padding = 0x91;                                                      //Pendding Bytes for dummy Bytes of Data (Value = 0x23)
        const Byte Connect_Command = 0xE8;                                              //0xE8 is Connect Command
        const Byte Upload_Command = 0xD5;                                               //0xD5 is Upload Profile data Command
        const Byte Read_data_Command = 0x3A;                                            //0x3A is read data command
        const Byte ETX = 0x33;                                                          //End of Package Transmittion
        //Byte ACK = 0x06;                                                          //ACK = Data send Correct
        //Byte ERROR = 0xEA;                                                        //ACK = Data Send Error

        //Define Variable for CRC
        Byte CRC_Low, CRC_High;
        int Length_Data = 25;
        UInt32 CRC;

        //Respond time FiO2
        Int16 RespondTime = 5;

        UInt16[] FiO2_graph = new UInt16[50];
        UInt16[] SpO2_graph = new UInt16[50];

        //Check conditon
        bool OxygenSat_Check, FiO2_Check , Alarm_Check, Prefer_FiO2_Check, RespondTime_Check = true;

        public Form1()
        {
            InitializeComponent();
            //Set Default Program
            AlarmLevel1 = 0;
            AlarmLevel2 = 0;
            AlarmL1_numericUpDown.Value = 1;
            AlarmL2_numericUpDown.Value = 2;
            BaudRate = 115200;                                                          // Set Default Baud Rate
            OxygenSatMin_textBox.Text = "87";
            OxygenSatMax_textBox.Text = "87";
            BaudRate_textBox.Text = "115200";
            

            //Define constant in Data out Package
            Data_Package[0] = Convert.ToByte('$');                                      // '$' is Head of Package Value
            Data_Package[2] = 0xFF;                                                     // Data_out[2] = 0xFF is Start of Data Package (SOH)
            Data_Package[39] = ETX;                                                     // Data_out[39] = ETX is End of Transmitted byte 

            //Disable FiO2 Value Forum
            Respond_time_textBox.Enabled = true;
            FiO2Max_numericUpDown.Enabled = false;
            FiO2Min_numericUpDown1.Enabled = false;

            //Respond time
            Respond_time_textBox.Text = "" + RespondTime;

            //Default Mode
            ModeFiO2_comboBox.SelectedIndex = 0;                                         // Default Auto mode
            Respond_time_textBox.Enabled = true;
            FiO2Max_numericUpDown.Enabled = false;
            FiO2Min_numericUpDown1.Enabled = false;

            for (UInt16 count = 0; count < 50; count++)
            {
                FiO2_graph[count] = Convert.ToUInt16( count + 21);
                SpO2_graph[count] = Convert.ToUInt16( 100 - count);
            }
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void OxygenSatMax_trackBar1_Scroll(object sender, EventArgs e)
        {            
            OxygenSatMax_textBox.Text = "" + OxygenSatMax_trackBar1.Value;            //Show Oxygen Saturation Value
        }

        /*
            Package of Data 
         * Length 28 Bytes
         * Byte 0 : Head of Bytes : "$"
         * Byte 1 : Command : Connect (0xE8), Upload (0xD5), Read data (0x3A)
         * Byte 2 : SOH     : 0xFF
         * Byte 3 - 24: Data (if don't have data replace with Padding Bytes (0x23) (Padding Bytes : 22 - Data))
         *      1.) Hospital Number 13 Bytes (Bytes : 3-15)
         *      2.) Oxygen Saturation max (1 Byte) (Byte: 16)
         *      3.) Oxygen Saturation min (1 Byte) (Byte: 17)
         *      4.) Respond time (1 Byte) (Byte: 18)
         *      5.) Prefered FiO2 (1 Byte)(Byte: 19)
         *      6.) Select Mode (Byte: 20)
         *              Range Mode(0xB7)
         *              Auto Mode (0xA2)
         *      7.) if selected Range mode : FiO2 Max (Byte 21), FiO2 Min (Byte 22)
         *          else selected Auto mode: Padding (0x91) (2 Bytes) (Byte : 21-22)
         *      8.) Alarm Level 1(Byte 23) and Alarm Level 2 (Byte 24)
         * Byte 25-26: CRC-16 Modbus(2 Bytes) (Byte 25: CRC-High, Byte 26: CRC-Low)
         * Byte 27 : End of Transmission (ETX) (0x03)
         *      
         *
        */

        private void Connect_button_Click(object sender, EventArgs e)
        {
            BaudRate = Convert.ToInt32(BaudRate_textBox.Text);
            //ComPort = Convert.ToUInt16(Comport_textBox.Text);
            if (Convert.ToByte(Comport_textBox.Text) != 0)
            {
                if (!serialPort1.IsOpen)
                {
                    /* Setting Serial Comport */
                    //serialPort1.PortName = Convert.ToString( SerialPort.GetPortNames());
                    serialPort1.PortName = "COM" + Comport_textBox.Text;
                    serialPort1.BaudRate = BaudRate;
                    serialPort1.DataBits = 8;
                    serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);

                    serialPort1.Open();
                    ConnectStatus_richTextBox.Text = "Port Openned";
                }

                /* Connect Command */
                Data_Package[1] = Connect_Command;
                for (Byte i = 3; i < 25; i++)
                {
                    Data_Package[i] = Padding;                                 //Pendding Bytes
                }
                CRC_CALCULATE_TX();
                Data_Package[25] = CRC_High;
                Data_Package[26] = CRC_Low;
                Data_Package[27] = ETX;

                // serialPort1.Write("Data for sendding");                  command for sendding data
                //serialPort1.Write("a");
                serialPort1.Write(Data_Package, 0, 27);

                ConnectStatus_richTextBox.Text = "Connected";
                connected = true;
            }

            else
            {
                MessageBox.Show("Error Comport: Comport Number available at Device Manager ","ERROR : ComPort");
            }
        }

        
        private void Upload_button_Click_1(object sender, EventArgs e)
        {
            if (connected == true)
            {
                condition = Check_Condition();
                if(condition == true)
                {
                    Data_Package[1] = Upload_Command;
                    //i = 0;

                    /* Hospital Number */
                    Data_Package[3]  = Convert.ToByte(Convert.ToInt64(Hospital_Number)/1000000000000);
                    Data_Package[4] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 1000000000000) / 100000000000);
                    Data_Package[5] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 100000000000) / 10000000000);
                    Data_Package[6] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 10000000000) / 1000000000);
                    Data_Package[7] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 1000000000) / 100000000);
                    Data_Package[8] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 100000000) / 10000000);
                    Data_Package[9] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 10000000) / 1000000);
                    Data_Package[10] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 1000000) / 100000);
                    Data_Package[11] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 100000) / 10000);
                    Data_Package[12] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 10000) / 1000);
                    Data_Package[13] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 1000) / 100);
                    Data_Package[14] = Convert.ToByte((Convert.ToInt64(Hospital_Number) % 100) / 10);
                    Data_Package[15] = Convert.ToByte(Convert.ToInt64(Hospital_Number) % 10);

                    Data_Package[16] = Convert.ToByte(OxygenSatMax_trackBar1.Value);
                    Data_Package[17] = Convert.ToByte(OxygenSatMin_trackBar.Value);
                    Data_Package[18] = Convert.ToByte(Respond_time_textBox.Text);
                    Data_Package[19] = Convert.ToByte(Prefer_FiO2_numericUpDown.Value);

                    int selectedIndex = ModeFiO2_comboBox.SelectedIndex;
                    if (selectedIndex == 0)
                    {
                        /* Select: Auto Mode */
                        Data_Package[20] = 0xA2;
                        Data_Package[21] = Padding;
                        Data_Package[22] = Padding;
                    }
                    else if (selectedIndex == 1)
                    {
                        /* Select : Range Mode */
                        Data_Package[20] = 0xB7;
                        Data_Package[21] = Convert.ToByte(FiO2Max_numericUpDown.Value);
                        Data_Package[22] = Convert.ToByte(FiO2Min_numericUpDown1.Value);
                    }

                    AlarmLevel1 = Convert.ToByte(AlarmL1_numericUpDown.Value);
                    AlarmLevel2 = Convert.ToByte(AlarmL2_numericUpDown.Value);

                    /* Alarm Data to the Transmit Buffer */
                    Data_Package[23] = AlarmLevel1;
                    Data_Package[24] = AlarmLevel2;

                    /* Calculate CRC 16 - ModBus */
                    CRC_CALCULATE_TX();
                    Data_Package[25] = CRC_High;
                    Data_Package[26] = CRC_Low;

                    //ETX is fil ready

                    /* Send Data to serial port */
                    serialPort1.Write(Data_Package, 0, 27);

                    //Wait ACK 
                }

            }
            else if (connected == false)
            {
                MessageBox.Show("Plase Click the Connect button before", "Warnning");
            }
        }

        private static void DataReceivedHandler(object sender,SerialDataReceivedEventArgs e)
        {
            String ACK_Respond;
            //String Resp_Complete, Resp_Error;
            //const Byte ACK = 0x41;                                                          //ACK = Data send Correct ('A')
            //const Byte ERROR = 0x65;                                                        //ACK = Data send Correct ('e')

            SerialPort sp = (SerialPort)sender;
            ACK_Respond = sp.ReadExisting();
            /*
             * ACK Respond back from microcontroller 
             * if ACK_Respond = 'A'     :   Correct Data send
             * if ACK_Respond = 'e'     :   Error Data send
             * if ACK_Respond = 0x45    :   Error cannot found the profile record of this Hospital Number
             * if ADC_Respond = 0xC3    :   Prepear receive data from SD card
            */
            if (ACK_Respond == "A")
            {
                MessageBox.Show("ACK From Microcontroller : Complete", "Show ACK");

            }
            else if (ACK_Respond == "e")
            {
                MessageBox.Show("ACK Form Microcontroller : ERROR","Show ACK");
            }
  //          else if (Convert.ToByte(ACK_Respond) == 0x45)
//            {
                /* use for read data form SD card and send to GUI for plot profile record */
  //              MessageBox.Show("The Profile record cannot found. Please check the Hospital Number.","Show ACK");
//            }
//            else if (Convert.ToByte(ACK_Respond) == 0xC3)
//            {
            //
            //}*/
            
        }

        /* CRC Calculate --------------------------------------------------------------------------------*/
        /* CRC 16 - Modbus */
        private void CRC_CALCULATE_TX()
        {
            Byte i;
            CRC = 0xFFFF;
            for (i = 0; i < Length_Data; i++)
            {
                CRC = TX_CRC(CRC, Data_Package[i]);
            }
            CRC_Low = Convert.ToByte(CRC & 0x00FF);                                                              //   Low byte calculation
            CRC_High = Convert.ToByte((CRC & 0xFF00) / 256);                                                     //  High byte calculation
        }

        private UInt32 TX_CRC(UInt32 crc, int data)
        {
            const UInt32 Poly16 = 0xA001;
            UInt32 LSB;
            Byte i;
            crc = Convert.ToUInt32(((crc ^ data) | 0xFF00) & (crc | 0x00FF));
            for (i = 0; i < 8; i++)
            {
                LSB = (crc & 0x0001);
                crc = crc / 2;
                if (LSB == 0x0001)
                {
                    crc = crc ^ Poly16;
                }
            }
            return (crc);
        }

        private void OxygenSatMin_trackBar_Scroll(object sender, EventArgs e)
        {
            OxygenSatMin_textBox.Text = "" + OxygenSatMin_trackBar.Value;
        }

        private void ModeFiO2_comboBox_SelectedIndexChanged(object sender, EventArgs e)
        {   
            /*
             * SelectMode
             * index = 0 -> select Mode : Auto Mode
             * index = 1 -> select Mode : Range Mode
             */
            int selectedIndex = ModeFiO2_comboBox.SelectedIndex;
            if (selectedIndex == 0)
            {
                /* Select: Auto Mode */
                Respond_time_textBox.Enabled = true;
                FiO2Max_numericUpDown.Enabled = false;
                FiO2Min_numericUpDown1.Enabled = false;
                //Data_Package[21] = Padding;
                //Data_Package[22] = Padding;

            }
            else if (selectedIndex == 1)
            {
                /* Select : Range Mode */
                Respond_time_textBox.Enabled = true;
                FiO2Max_numericUpDown.Enabled = true;
                FiO2Min_numericUpDown1.Enabled = true;
                //Data_Package[21] = Convert.ToByte(FiO2Max_numericUpDown.Value);
                //Data_Package[22] = Convert.ToByte(FiO2Min_numericUpDown1.Value);
            }
           
        }

        /* Credit List name : Term of Deverloper */
        private void Credit_linkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            MessageBox.Show("Team of Deverloper : \n"+
                            "Pornchai\t\t Chayagorn, Ph.D\n"+
                            "Phattaradanai\t Kiratiwudhikul\n"+
                            "Kaned\t\t Patisampitawong\n"+
                            "Wicha\t\t Chongsakool\n","Team of Deverloper");
        }

        private void Respond_time_textBox_TextChanged(object sender, EventArgs e)
        {

            /* Program will run when Press Enter */
            if (Respond_time_textBox.Text != "0")
            {

            }
            else
            {
                MessageBox.Show("Enter the Respond time more than zero, Please", "Error");
            } 
        }

        private bool Check_Condition()
        {
            /*
             * Check Condition of the Assign Profile
             * Check Condition : Oxygen Saturation Assignment
             */
            OxygenSat_Check = true;
            FiO2_Check = true;
            Alarm_Check = true;

            RespondTime = Convert.ToInt16(Respond_time_textBox.Text);
            Hospital_Number = Hospital_Number_textBox.Text;

            if (OxygenSatMax_trackBar1.Value < OxygenSatMin_trackBar.Value)
            {
                OxygenSat_Check = false;
                MessageBox.Show("Maximum Oxygen Saturation must be greater than Minimum Oxygen Saturation","ERROR : Oxygen Saturation");
            }

            /* Check Condition : FiO2 Value Assignment */
            if (FiO2Max_numericUpDown.Value < FiO2Min_numericUpDown1.Value)
            {
                FiO2_Check = false;
                MessageBox.Show("Maximum FiO2 must be greater than Minimum FiO2", "Error : FiO2");
            }

            if (AlarmL1_numericUpDown.Value > AlarmL2_numericUpDown.Value)
            {
                Alarm_Check = false;
                MessageBox.Show("Alarm Level 2 must be greater than Alarm Level 1", "Error : Alarm Level");
            }

            /* Check : Prefer FiO2 */
            if (Prefer_FiO2_numericUpDown.Value >= FiO2Min_numericUpDown1.Value & Prefer_FiO2_numericUpDown.Value <= FiO2Max_numericUpDown.Value)
            {
                Prefer_FiO2_Check = true;
            }
            else
            {
                Prefer_FiO2_Check = false;
                MessageBox.Show("Prefer FiO2 have to between Minimum FiO2 and Maximun FiO2", "ERROR : Prefer FiO2");
            }

            /* Check Prefer */
            if (RespondTime > 0)
            {
                RespondTime_Check = true;
            }
            else
            {
                RespondTime_Check = false;
                MessageBox.Show("Respond time must be greater than zero","ERROR : Respond Time");
            }

            //Summary
            if (OxygenSat_Check & FiO2_Check & Alarm_Check & Prefer_FiO2_Check & RespondTime_Check == true)
            {
                condition = true;
            }
            else
            {
                condition = false;
            }
            return condition;
        }

        private void Load_Button_Click(object sender, EventArgs e)
        {
            /*
             Description : this fucntion will send request command for get the data of SpO2 and FiO2 form the microcontroller
             */
            if (connected == true)
            {
                string sHN_plotGraph;
                sHN_plotGraph = Load_HN_TextBox.Text;    // getting the HN for send request command to microcontroller

                /* Transmision request read data section */
                Data_Package[1] = Read_data_Command;

                /* Hospital Number section (Need to improve : create function for convert Hospital Number) */
                Data_Package[3] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 1000000000000) / 100000000000);
                Data_Package[5] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 10000000000) / 1000000000);
                Data_Package[7] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 1000000000) / 100000000);
                Data_Package[8] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 100000000) / 10000000);
                Data_Package[9] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 10000000) / 1000000);
                Data_Package[10] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 1000000) / 100000);
                Data_Package[11] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 100000) / 10000);
                Data_Package[12] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 10000) / 1000);
                Data_Package[13] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 1000) / 100);
                Data_Package[14] = Convert.ToByte((Convert.ToUInt64(sHN_plotGraph) % 100) / 10);
                Data_Package[15] = Convert.ToByte(Convert.ToUInt64(sHN_plotGraph) % 10);
                /* Padding section */
                for (Byte i = 16; i < 25; i++)
                {
                    Data_Package[i] = Padding;                                 //Pendding Bytes
                }
                CRC_CALCULATE_TX();
                Data_Package[25] = CRC_High;
                Data_Package[26] = CRC_Low;
                Data_Package[27] = ETX;

                /* Send Data to serial port */
                //serialPort1.Write(Data_Package, 0, 27);

                /* Wait data back form MCU*/
                for (Byte uiData_number = 0; uiData_number < 50; uiData_number++)
                {
                    this.plot_graph_Chart.Series["FiO2"].Points.AddXY(Convert.ToString(uiData_number), FiO2_graph[uiData_number]);  // plot FiO2 graph
                    this.plot_graph_Chart.Series["SpO2"].Points.AddXY(Convert.ToString(uiData_number), SpO2_graph[uiData_number]);  // plot SpO2 graph
                }
            }
            else
            {
                MessageBox.Show("Plase Click the Connect button before", "Warnning");
            }
        }

      
    }
}
